package com.symaster.common.swing.dialog;

import com.formdev.flatlaf.util.StringUtils;
import com.symaster.common.image.BmpHeader;
import com.symaster.common.swing.util.SwingUtil;
import com.symaster.common.swing.util.ThreadPoolUtil;
import com.symaster.common.util.IOUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashSet;
import java.util.Set;

public class ImageShowDialog extends JDialog {
    private JPanel contentPane;
    private JButton buttonCancel;
    private JProgressBar progressBar1;
    private JPanel center_panel;
    private JScrollPane scroll_panel;
    private ImageShowPanel imageShowPanel;

    public ImageShowDialog() {
        initPage();
        initListener();
    }

    public static void main(String[] args) {
        ImageShowDialog dialog = new ImageShowDialog();
        dialog.open("S:\\imageai\\cp\\2022-04-23\\92204235195.bmp");
        System.exit(0);
    }

    private void initListener() {
        buttonCancel.addActionListener(e -> onCancel());
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                onCancel();
            }
        });
        contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    }

    private void initPage() {
        scroll_panel.getVerticalScrollBar().setUnitIncrement(20);
        scroll_panel.getHorizontalScrollBar().setUnitIncrement(20);
        setPreferredSize(new Dimension(600, 800));
        setContentPane(contentPane);
        setModal(true);
        pack();
        SwingUtil.toCenter(this);
    }

    private void onCancel() {
        dispose();
    }

    public void open(String filePathName) {

        int typeI = filePathName.lastIndexOf(".");
        if (typeI < 0) {
            JOptionPane.showMessageDialog(this, "暂时只支持.bmp图片", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        String type = filePathName.substring(typeI);
        if (!type.equalsIgnoreCase(".bmp")) {
            JOptionPane.showMessageDialog(this, "暂时只支持.bmp图片", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        File file = new File(filePathName);
        if (!file.isFile()) {
            JOptionPane.showMessageDialog(this, "指定文件不存在", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }

        ThreadPoolUtil.execute(() -> {
            try {
                JPanel pane1 = new JPanel();
                imageShowPanel = new ImageShowPanel(filePathName, (i, max) -> SwingUtilities.invokeLater(() -> progressUpdate(i, max, pane1, scroll_panel)));
                pane1.setLayout(new BorderLayout());
                pane1.add(imageShowPanel, BorderLayout.WEST);
                center_panel.add(pane1);
            } catch (Exception e) {
                JOptionPane.showMessageDialog(this, e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
                dispose();
            }
        });
        setVisible(true);
    }

    private void progressUpdate(double v, double max, JComponent... components) {
        if (components != null) {
            for (JComponent component : components) {
                component.updateUI();
            }
        }
        progressBar1.setMaximum((int) Math.round(max * 10));
        progressBar1.setValue((int) Math.round(v * 10));
    }

    {
        // GUI initializer generated by IntelliJ IDEA GUI Designer
        // >>> IMPORTANT!! <<<
        // DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout(0, 0));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new BorderLayout(0, 0));
        contentPane.add(panel1, BorderLayout.WEST);
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new BorderLayout(0, 0));
        contentPane.add(panel2, BorderLayout.EAST);
        final JPanel panel3 = new JPanel();
        panel3.setLayout(new BorderLayout(0, 0));
        contentPane.add(panel3, BorderLayout.NORTH);
        final JPanel panel4 = new JPanel();
        panel4.setLayout(new BorderLayout(0, 0));
        panel4.setPreferredSize(new Dimension(0, 5));
        contentPane.add(panel4, BorderLayout.SOUTH);
        progressBar1 = new JProgressBar();
        panel4.add(progressBar1, BorderLayout.CENTER);
        final JPanel panel5 = new JPanel();
        panel5.setLayout(new BorderLayout(0, 0));
        contentPane.add(panel5, BorderLayout.CENTER);
        final JPanel panel6 = new JPanel();
        panel6.setLayout(new BorderLayout(0, 0));
        panel5.add(panel6, BorderLayout.SOUTH);
        buttonCancel = new JButton();
        buttonCancel.setText("Cancel");
        panel6.add(buttonCancel, BorderLayout.EAST);
        scroll_panel = new JScrollPane();
        panel5.add(scroll_panel, BorderLayout.CENTER);
        center_panel = new JPanel();
        center_panel.setLayout(new BorderLayout(0, 0));
        scroll_panel.setViewportView(center_panel);
    }

    /** @noinspection ALL */
    public JComponent $$$getRootComponent$$$() {
        return contentPane;
    }

}

class ImageShowPanel extends JPanel {

    private BufferedImage image;
    private Set<ProgressUpdateListener> progressUpdateListeners;

    public ImageShowPanel(String filePathName) {
        if (StringUtils.isEmpty(filePathName)) {
            throw new IllegalArgumentException("StringUtils.isEmpty(filePathName)");
        }

        File file = new File(filePathName);
        if (!file.isFile()) {
            throw new NullPointerException(String.format("'%s' 文件不存在", filePathName));
        }

        ThreadPoolUtil.execute(() -> loadImage(file));
    }

    public ImageShowPanel(String filePathName, ProgressUpdateListener listener) {
        if (StringUtils.isEmpty(filePathName)) {
            throw new IllegalArgumentException("StringUtils.isEmpty(filePathName)");
        }

        File file = new File(filePathName);
        if (!file.isFile()) {
            throw new NullPointerException(String.format("'%s' 文件不存在", filePathName));
        }

        if (listener != null) addProgressUpdateListener(listener);
        ThreadPoolUtil.execute(() -> loadImage(file));
    }

    private static int toInt(byte b) {
        return (int) b & 0xff;
    }

    private void loadImage(File file) {
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            BmpHeader bmpHeader = new BmpHeader(fileInputStream);
            int bitCount = bmpHeader.getiBitCount();
            if (24 != bitCount) {
                throw new RuntimeException(String.format("'%s' 暂不支持此图片", file.getPath()));
            }
            int iWidth = bmpHeader.getiWidth();
            int iHeight = bmpHeader.getiHeight();
            int pxOffset = 13;

            int width = iWidth / pxOffset;
            int height = iHeight / pxOffset;
            int lineSize = (iWidth * bitCount + 31) / 32 * 4;

            image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
            Graphics graphics = image.getGraphics();

            byte[] row = new byte[pxOffset * 3];

            for (int y = height; y > 0; y--) {
                for (int x = 0; x < width; x++) {
                    fileInputStream.read(row, 0, row.length);
                    graphics.setColor(new Color(toInt(row[2]), toInt(row[1]), toInt(row[0])));
                    graphics.drawRect(x, y, 0, 0);
                }

                if (y % 3 == 0) {
                    if (!isShowing()) return;
                    progressUpdateListener(height - y + 1, height);
                }
                fileInputStream.skip(((long) pxOffset * lineSize) + (lineSize - ((long) width * row.length)));
            }

            progressUpdateListener(height, height);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            IOUtil.close(fileInputStream);
        }
    }

    private void progressUpdateListener(double i, double max) {
        if (progressUpdateListeners == null) {
            return;
        }

        for (ProgressUpdateListener progressUpdateListener : progressUpdateListeners) {
            progressUpdateListener.handler(i, max);
        }
    }

    @Override
    public void paint(Graphics g) {
        setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
        g.drawImage(image, 0, 0, this);
    }

    public void addProgressUpdateListener(ProgressUpdateListener listener) {
        if (progressUpdateListeners == null) {
            progressUpdateListeners = new HashSet<>();
        }
        progressUpdateListeners.add(listener);
    }

    public void removeProgressUpdateListener(ProgressUpdateListener listener) {
        if (progressUpdateListeners == null) {
            return;
        }
        progressUpdateListeners.remove(listener);
    }

    public interface ProgressUpdateListener {
        void handler(double i, double max);
    }
}